﻿namespace Pub.Class
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Threading;

    public class DownFile
    {
        private Action<DownFileInfo> action;
        private Action<DownFileInfo> done;
        private Action<Exception> error;
        private DownFileInfo info;
        private readonly object locker;
        private List<List<long>> readFT;
        private List<string> tempFiles;
        private Thread[] thread;
        private int threadCompleteNum;

        public DownFile(string fileUrl, string savePath)
        {
            this.info = new DownFileInfo();
            this.tempFiles = new List<string>();
            this.readFT = new List<List<long>>();
            this.locker = new object();
            this.info.FileUrl = fileUrl;
            this.info.SavePath = savePath;
            this.info.FileName = fileUrl.GetFileName();
        }

        public DownFile(string fileUrl, string savePath, int threahNum)
        {
            this.info = new DownFileInfo();
            this.tempFiles = new List<string>();
            this.readFT = new List<List<long>>();
            this.locker = new object();
            this.info.ThreadNum = threahNum;
            this.info.FileUrl = fileUrl;
            this.info.SavePath = savePath;
            this.info.FileName = fileUrl.GetFileName();
        }

        public DownFile Action(Action<DownFileInfo> action)
        {
            this.action = action;
            return this;
        }

        private void Complete()
        {
            Stream output = null;
            BinaryWriter writer = null;
            try
            {
                output = new FileStream(string.Format(@"{0}\{1}", this.info.SavePath, this.info.FileName), FileMode.Create);
                writer = new BinaryWriter(output);
                foreach (string str in this.tempFiles)
                {
                    using (FileStream stream2 = new FileStream(str, FileMode.Open))
                    {
                        BinaryReader reader = new BinaryReader(stream2);
                        writer.Write(reader.ReadBytes((int) stream2.Length));
                        reader.Close();
                    }
                    System.IO.File.Delete(str);
                }
            }
            catch (Exception exception)
            {
                if (this.error.IsNotNull())
                {
                    this.error(exception);
                }
            }
            finally
            {
                writer.Close();
                output.Close();
            }
        }

        public DownFile Done(Action<DownFileInfo> done)
        {
            this.done = done;
            return this;
        }

        private void Download()
        {
            Stream responseStream = null;
            Stream stream2 = null;
            HttpWebResponse response = null;
            try
            {
                string filename = string.Format(@"{0}\{1}{2}.dat", this.info.SavePath, this.info.FileName, Thread.CurrentThread.Name);
                bool flag = FileDirectory.FileExists(filename);
                this.tempFiles.Add(filename);
                HttpWebRequest request = (HttpWebRequest) WebRequest.Create(this.info.FileUrl);
                long num = this.readFT[Convert.ToInt32(Thread.CurrentThread.Name)][0];
                long num2 = this.readFT[Convert.ToInt32(Thread.CurrentThread.Name)][1];
                if (flag)
                {
                    long num3 = FileDirectory.FileSize(filename);
                    lock (this.locker)
                    {
                        this.info.DownloadSize += num3;
                    }
                    num += num3;
                }
                request.AddRange((int) num, (int) num2);
                response = (HttpWebResponse) request.GetResponse();
                responseStream = response.GetResponseStream();
                stream2 = new FileStream(filename, flag ? FileMode.Append : FileMode.Create);
                byte[] buffer = new byte[0x400];
                int count = responseStream.Read(buffer, 0, 0x400);
                while (count > 0)
                {
                    lock (this.locker)
                    {
                        this.info.DownloadSize += count;
                    }
                    stream2.Write(buffer, 0, count);
                    count = responseStream.Read(buffer, 0, 0x400);
                    if (this.action.IsNotNull())
                    {
                        this.action(this.info);
                    }
                }
                lock (this.locker)
                {
                    this.threadCompleteNum++;
                }
            }
            catch (Exception exception)
            {
                if (this.error.IsNotNull())
                {
                    this.error(exception);
                }
            }
            finally
            {
                if (responseStream.IsNotNull())
                {
                    responseStream.Close();
                }
                if (stream2.IsNotNull())
                {
                    stream2.Close();
                }
                if (response.IsNotNull())
                {
                    response.Close();
                }
            }
            if (this.threadCompleteNum == this.info.ThreadNum)
            {
                this.Complete();
                this.info.IsComplete = true;
                if (this.done.IsNotNull())
                {
                    this.done(this.info);
                }
            }
        }

        public DownFile Error(Action<Exception> error)
        {
            this.error = error;
            return this;
        }

        public DownFile FileName(string fileName)
        {
            this.info.FileName = fileName;
            return this;
        }

        public void Pause()
        {
            foreach (Thread thread in this.thread)
            {
                if (thread.ThreadState == ThreadState.Running)
                {
                    thread.Suspend();
                }
            }
        }

        public void Start()
        {
            ThreadStart start = null;
            if (this.thread.IsNull())
            {
                if (start == null)
                {
                    start = delegate {
                        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(this.info.FileUrl);
                        HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                        this.info.ExtName = response.ResponseUri.ToString().GetExtension();
                        this.info.FileSize = response.ContentLength;
                        int num = (int) (this.info.FileSize / ((long) this.info.ThreadNum));
                        int num2 = (int) (this.info.FileSize % ((long) this.info.ThreadNum));
                        request.Abort();
                        response.Close();
                        this.thread = new Thread[this.info.ThreadNum];
                        for (int j = 0; j < this.info.ThreadNum; j++)
                        {
                            List<long> item = new List<long> {
                                (long) (j * num)
                            };
                            if ((num2 != 0) && ((this.info.ThreadNum - 1) == j))
                            {
                                item.Add((long) ((((j * num) + num) + num2) - 1));
                            }
                            else
                            {
                                item.Add((long) (((j * num) + num) - 1));
                            }
                            this.readFT.Add(item);
                            this.thread[j] = new Thread(new ThreadStart(this.Download));
                            this.thread[j].Name = j.ToString();
                            this.thread[j].IsBackground = true;
                            this.thread[j].Start();
                        }
                    };
                }
                new Thread(start).Start();
            }
            else
            {
                foreach (Thread thread in this.thread)
                {
                    if ((thread.ThreadState == ThreadState.SuspendRequested) || (thread.ThreadState == ThreadState.Suspended))
                    {
                        thread.Resume();
                    }
                }
            }
        }

        public void Stop()
        {
            foreach (Thread thread in this.thread)
            {
                if (thread.ThreadState == ThreadState.Running)
                {
                    thread.Abort();
                }
            }
            this.thread = null;
        }
    }
}

